package com.zeng.sys.authmd.servicemodule.service.serviceimpl;

import com.baomidou.mybatisplus.core.conditions.AbstractWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.zeng.nicecore.constant.IgnoreConstant;
import com.zeng.nicecore.util.BeanUtil;
import com.zeng.nicecore.util.IgnoreStringUtil;
import com.zeng.nicecore.wrapper.QWrapper;
import com.zeng.sys.authmd.apimodule.service.RolePermissionService;
import com.zeng.sys.authmd.apimodule.service.RoleService;
import com.zeng.sys.authmd.apimodule.service.UserRoleService;
import com.zeng.sys.authmd.apimodule.service.com.zeng.sys.authmd.apimodule.constant.PermissionType;
import com.zeng.sys.authmd.apimodule.vo.*;
import com.zeng.sys.authmd.servicemodule.convert.PermissionVoConvert;
import com.zeng.sys.authmd.servicemodule.entity.Role;
import com.zeng.sys.authmd.servicemodule.mapper.PermissionMapper;
import com.zeng.sys.authmd.servicemodule.entity.Permission;
import com.zeng.sys.authmd.apimodule.service.PermissionService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

@Service
@Transactional
public class PermissionServiceImpl extends PermissionVoConvert implements PermissionService {

    @Autowired
    PermissionMapper permissionMapper;

    @Autowired
    PermissionVoConvert permissionVoConvert;

    @Autowired
    UserRoleService userRoleService;

    @Autowired
    RoleService roleService;

    @Autowired
    RolePermissionService rolePermissionService;

    @Override
    public PermissionVo addOne(PermissionVo permissionVo) {
        Permission permission = Permission.builder().build();
        BeanUtils.copyProperties(permissionVo, permission, IgnoreStringUtil.ignoreExclude());
        int insert = permissionMapper.insert(permission);
        return BeanUtil.beanToVo(permission, permissionVo);
    }

    @Override
    public PermissionVo getOneByCode(String code) {

        Permission permission = this.permissionMapper.selectById(code);
        PermissionVo permissionVo = BeanUtil.beanToVo(permission, new PermissionVo());

        return permissionVo;
    }

    @Override
    public Integer update(PermissionVo permissionVo) {
        Permission permission = BeanUtil.VoToBean(permissionVo,
                new Permission(),
                IgnoreStringUtil.ignoreExclude(IgnoreConstant.code.getValue()));
        return this.permissionMapper.updateById(permission);
    }

    @Override
    public Integer delete(String code) {
        rolePermissionService.deleteByPermissionCode(code);
        return this.permissionMapper.deleteById(code);
    }

    @Override
    public Integer batchDelete(List<String> codes) {
        rolePermissionService.batchDeleteByPermissionCode(codes);
        return this.permissionMapper.deleteBatchIds(codes);
    }

    @Override
    public List<PermissionVo> findPage(Page page, PermissionVo permissionVo) {
        this.permissionMapper.selectPage(page, this.getWrapper(permissionVo));
        List orders = page.getRecords();
        List<PermissionVo> permissionVos = new ArrayList<>();
        orders.forEach(e -> {
            permissionVos.add(BeanUtil.beanToVo(e, new PermissionVo()));
        });
        page.setRecords(null);
        return permissionVos;
    }

    @Override
    public List<PermissionVo> findAll(PermissionVo permissionVo) {
        List orders = this.permissionMapper.selectList(this.getWrapper(permissionVo));
        List<PermissionVo> permissionVos = new ArrayList<>();
        orders.forEach(e -> {
            permissionVos.add(BeanUtil.beanToVo(e, new PermissionVo()));
        });
        return permissionVos;
    }

    @Override
    public Integer count(PermissionVo permissionVo) {
        Integer integer = this.permissionMapper.selectCount(this.getWrapper(permissionVo));
        return integer;
    }

    @Override
    public List<MenuVo> listAllMenu() {
        // 只设计2级菜单
        QueryWrapper<Permission> queryWrapper = new QWrapper<>();
        queryWrapper.eq(Permission.Fields.type, PermissionType.MENU);
        List<Permission> permissions = permissionMapper.selectList(queryWrapper);
        List<Permission> rootMenus = permissions.stream().filter(e -> StringUtils.isEmpty(e.getParentCode())).collect(Collectors.toList());
        List<Permission> childrenMunu = permissions.stream().filter(e -> StringUtils.isNotEmpty(e.getParentCode())).collect(Collectors.toList());
        List<PermissionVo> rootPermissionVos = toPermissionVoList(rootMenus);
        for (PermissionVo permissionVo : rootPermissionVos) {
            permissionVo.setChildrens(new ArrayList<>());
            for (Permission permission : childrenMunu) {
                if (permission.getParentCode().equals(permissionVo.getCode())) {
                    permissionVo.getChildrens().add(toPermissionVo(permission));
                }
            }
        }
        return toMenuVoList(rootPermissionVos);
    }

    @Override
    public List<MenuVo> listAllMenu(UserVo userVo) {
        List<PermissionVo> renturnPermission = new ArrayList<>();
        List<UserRoleVo> userRoleVos = userRoleService.listUserRoleByUserCode(userVo.getCode());
        List<RoleVo> roleVos = roleService.listByCodes(userRoleVos.stream().map(UserRoleVo::getRoleCode).collect(Collectors.toList()));

        List<RolePermissionVo> rolePermissionVos = rolePermissionService.listPermissionByRoleCodes(roleVos.stream().map(RoleVo::getCode).collect(Collectors.toList()));

        List<PermissionVo> permissionVos = listByCodesAndType(rolePermissionVos.stream().map(RolePermissionVo::getPermissionCode).collect(Collectors.toList()), PermissionType.MENU);
        List<PermissionVo> listPermissionOfMenu = listByType(PermissionType.MENU);
        List<PermissionVo> menuParents = listPermissionOfMenu.stream().filter(e -> StringUtils.isEmpty(e.getParentCode())).collect(Collectors.toList());
        Map<String, PermissionVo> map = new HashMap<>();
        for (PermissionVo menuParent : menuParents) {
            map.put(menuParent.getCode(), menuParent);
        }
        for (PermissionVo permissionVo : permissionVos) {
            if (StringUtils.isEmpty(permissionVo.getParentCode())) {
                continue;
            }
            PermissionVo parent = map.get(permissionVo.getParentCode());
            List<PermissionVo> childrens = parent.getChildrens();
            if (childrens == null) {
                parent.setChildrens(new ArrayList<>());
                renturnPermission.add(parent);
            }
            parent.getChildrens().add(permissionVo);
        }
        return toMenuVoList(renturnPermission);
    }

    @Override
    public List<PermissionVo> listByType(String type) {
        QueryWrapper<Permission> queryWrapper = new QWrapper<>();
        queryWrapper.eq(Permission.Fields.type, type);
        List<Permission> list = permissionMapper.selectList(queryWrapper);
        List<PermissionVo> permissionVos = this.toPermissionVoList(list);
        return permissionVos;
    }

    @Override
    public List<PermissionVo> listByCodesAndType(List<String> codes, String type) {
        if (codes == null) {
            return Collections.emptyList();
        }
        AbstractWrapper wrapper = this.getWrapper(null);
        wrapper.in("code", codes);
        wrapper.eq(Permission.Fields.type, type);
        List list = permissionMapper.selectList(wrapper);
        return toPermissionVoList(list);

    }

    @Override
    public Integer deleteMenu(String code) {
        QueryWrapper queryWrapper = new QWrapper<>();
        queryWrapper.eq(Permission.Fields.parentCode, code);
        queryWrapper.or();
        queryWrapper.eq("code", code);
        int delete = permissionMapper.delete(queryWrapper);
        return delete;
    }

    public AbstractWrapper getWrapper(PermissionVo permissionVo) {
        QueryWrapper<Permission> wrapper = new QWrapper<>();
        if (permissionVo != null) {
            if (StringUtils.isNotEmpty(permissionVo.getType())) {
                wrapper.eq(Permission.Fields.type, permissionVo.getType());
            }
            if (StringUtils.isNotEmpty(permissionVo.getName())) {
                wrapper.like(Permission.Fields.name, permissionVo.getName());
            }
            if (StringUtils.isNotEmpty(permissionVo.getUrl())) {
                wrapper.like(Permission.Fields.url, permissionVo.getUrl());
            }
            if (permissionVo.getAvailable() != null) {
                wrapper.eq(Permission.Fields.available, permissionVo.getAvailable());
            }

        }
        return wrapper;
    }
}
